package authorized

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/go-resty/resty/v2"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
	"time"
	"yundian/internel/pkg/dingo/global"
	"yundian/internel/pkg/utils"
)

const (
	redirectOauthURL       = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"
	webAppRedirectOauthURL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect"
	webAccessTokenURL      = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
	refreshAccessTokenURL  = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s"
	userInfoURL            = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN"
	checkAccessTokenURL    = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s"
	accessTokenURL         = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
	getTicketURL           = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"
)

var client = resty.New()

// 获取网页授权access_token
func GetWebAccessToken(code string, appid, secret string) (res ResWebAccessToken, err error) {
	urlStr := fmt.Sprintf(webAccessTokenURL, appid, secret, code)
	resp, err := client.R().Get(urlStr)
	//log.Println("获取用户accesstoken", string(resp.Body()))
	if err != nil {
		return
	}
	err = json.Unmarshal(resp.Body(), &res)
	if err != nil {
		return
	}
	if res.Errcode != 0 {
		err = fmt.Errorf("GetWebAccessToken error : errcode=%v , errmsg=%v", res.Errcode, res.Errmsg)
		return
	}
	return
}

func GetUserInfo(accessToken, openID string) (res WxUserInfo, err error) {
	urlStr := fmt.Sprintf(userInfoURL, accessToken, openID)
	resp, err := client.R().Get(urlStr)
	//log.Println("获取用户信息", string(resp.Body()))
	if err != nil {
		return
	}
	err = json.Unmarshal(resp.Body(), &res)
	if err != nil {
		return
	}
	if res.Errcode != 0 {
		err = fmt.Errorf("GetUserInfo error : errcode=%v , errmsg=%v", res.Errcode, res.Errmsg)
		return
	}
	return
}

// 获取普通access_token
func GetAccessToken(appid, secret string) (res ResAccessToken, err error) {
	urlStr := fmt.Sprintf(accessTokenURL, appid, secret)
	resp, err := client.R().Get(urlStr)
	if err != nil {
		return
	}
	err = json.Unmarshal(resp.Body(), &res)
	if err != nil {
		return
	}
	if res.Errcode != 0 {
		err = fmt.Errorf("GetUserAccessToken error : errcode=%v , errmsg=%v", res.Errcode, res.Errmsg)
		return
	}
	key := utils.Join("cgi-bin-Access-Token")
	global.Rdb.Set(context.Background(), key, res.AccessToken, time.Hour*1) // 过期时间1小时

	return
}

// 获取微信公众号access_token，存储缓存
func GetSaveAccessToken(appKey, appSecret string) (res ResAccessToken, err error) {
	urlStr := fmt.Sprintf(accessTokenURL, appKey, appSecret)
	key := utils.Join("cgi-bin-Access-Token")
	resp, err := client.R().Get(urlStr)
	if err != nil {
		return
	}
	err = json.Unmarshal(resp.Body(), &res)
	if err != nil {
		return
	}
	if res.Errcode != 0 {
		// 清除redis缓存中的token
		global.Rdb.Del(context.Background(), key)
		err = fmt.Errorf("GetUserAccessToken error : errcode=%v , errmsg=%v", res.Errcode, res.Errmsg)
		return
	}

	global.Rdb.Set(context.Background(), key, res.AccessToken, time.Hour*1) // 过期时间1小时

	return
}

func GetTicket(accessToken string) (res ResTicket, err error) {
	urlStr := fmt.Sprintf(getTicketURL, accessToken)
	resp, err := client.R().Get(urlStr)
	if err != nil {
		return
	}
	err = json.Unmarshal(resp.Body(), &res)
	if err != nil {
		return
	}
	if res.Errcode != 0 {
		err = fmt.Errorf("getTicket Error : errcode=%d , errmsg=%s", res.Errcode, res.Errmsg)
		return
	}
	return
}

//获取微信企业AccessToke
func GetWeChatGroupAccessToke(corpId, corpSecret string, placesId int) (res ResAccessToken, err error) {
	//corpId = "ww14e6e1e96fa1a578"
	//corpSecret = "-X_cCOnRDB9ItZjCEgt56jsY_x1K35ynQzlzlUM3Tyo"
	key := utils.Join(strconv.Itoa(placesId) + "-wx-Access-Token")
	urlStr := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s", corpId, corpSecret)
	resp, err := client.R().Get(urlStr)
	if err != nil {
		return
	}
	err = json.Unmarshal(resp.Body(), &res)
	if err != nil {
		return
	}
	if res.Errcode != 0 {
		// 清除redis缓存中的token
		global.Rdb.Del(context.Background(), key)
		err = fmt.Errorf("getTicket Error : errcode=%d , errmsg=%s", res.Errcode, res.Errmsg)
		return
	}

	global.Rdb.Set(context.Background(), key, res.AccessToken, time.Hour*1) // 过期时间1小时
	return
}

func GetWeChatGroupUserId(phone, accessToken string) string {
	bodyData := map[string]interface{}{
		"mobile": phone,
	}
	urlStr := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=%s", accessToken)

	payload, _ := json.Marshal(bodyData)

	headers := map[string]string{"Content-Type": "application/json"}

	resp, err := PostRequest(urlStr, headers, bytes.NewReader(payload))
	if err != nil {
		return ""
	}

	return resp["userid"].(string)
}

//获取钉钉AccessToken
func GetDingTalkAccessToken(accessTokenKey, appKey, appSecret string) (res ResAccessToken, err error) {
	//appKey = "ding02gdscrjiintcriw"
	//appSecret = "fRUjyqXJA5ELa8aF1hUuLFDGMxiBsPwxdF4nhavEChPXmOvYV7SwJYamMf9zYZy8"
	key := utils.Join(accessTokenKey)
	urlStr := fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", appKey, appSecret)
	resp, err := client.R().Get(urlStr)
	if err != nil {
		return
	}
	err = json.Unmarshal(resp.Body(), &res)
	if err != nil {
		return
	}
	if res.Errcode != 0 {
		// 清除redis缓存中的token
		global.Rdb.Del(context.Background(), key)
		err = fmt.Errorf("getTicket Error : errcode=%d , errmsg=%s", res.Errcode, res.Errmsg)
		return
	}

	global.Rdb.Set(context.Background(), key, res.AccessToken, time.Hour*1) // 过期时间1小时
	return
}

// 网页授权access_token
//type ResWebAccessToken struct {
//	AccessToken  string `json:"access_token"`
//	ExpiresIn    int    `json:"expires_in"`
//	RefreshToken string `json:"refresh_token"`
//	Scope        string `json:"scope"`
//	Openid       string `json:"openid"`
//	Unionid      string `json:"unionid"`
//	Errcode      int    `json:"errcode"`
//	Errmsg       string `json:"errmsg"`
//}
type ResWebAccessToken struct {
	AccessToken  string `json:"access_token"`
	ExpiresIn    int    `json:"expires_in"`
	RefreshToken string `json:"refresh_token"`
	Openid       string `json:"openid"`
	Scope        string `json:"scope"`
	Unionid      string `json:"unionid"`
	Errcode      int    `json:"errcode"`
	Errmsg       string `json:"errmsg"`
}

type WxUserInfo struct {
	Openid     string        `json:"openid"`
	Nickname   string        `json:"nickname"`
	Sex        int           `json:"sex"`
	Language   string        `json:"language"`
	City       string        `json:"city"`
	Province   string        `json:"province"`
	Country    string        `json:"country"`
	Headimgurl string        `json:"headimgurl"`
	Privilege  []interface{} `json:"privilege"`
	Unionid    string        `json:"unionid"`
	Errcode    int           `json:"errcode"`
	Errmsg     string        `json:"errmsg"`
}

//type WxUserInfo struct {
//	ID         int        `json:"id"`
//	Openid     string     `json:"openid"`
//	Nickname   string     `json:"nickname"`
//	Headimgurl string     `json:"headimgurl"`
//	Sex        int        `json:"sex"`
//	Province   string     `json:"province"`
//	City       string     `json:"city"`
//	Country    string     `json:"country"`
//	Name       string     `json:"name"`
//	Mobile     string     `json:"mobile"`
//	Address    string     `json:"address"`
//	CreatedAt  time.Time  `json:"created_at"`
//	UpdatedAt  time.Time  `json:"updated_at"`
//	DeletedAt  *time.Time `json:"deleted_at"`
//	Errcode    int        `json:"errcode"`
//	Errmsg     string     `json:"errmsg"`
//}

// 普通access_token
type ResAccessToken struct {
	AccessToken string `json:"access_token"`
	ExpiresIn   int    `json:"expires_in"`
	Errcode     int    `json:"errcode"`
	Errmsg      string `json:"errmsg"`
}

type ResTicket struct {
	Ticket    string `json:"ticket"`
	ExpiresIn int    `json:"expires_in"`
	Errcode   int    `json:"errcode"`
	Errmsg    string `json:"errmsg"`
}

type SignInfo struct {
	Appid     string `json:"appId"`
	NonceStr  string `json:"nonceStr"`
	TimeStamp string `json:"timeStamp"`
	Url       string `json:"url"`
	Signature string `json:"signature"`
}

// 生成随机字符串
func GetRandomString(l int) string {
	str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
	bytes := []byte(str)
	var result []byte
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

func PostRequest(url string, headers map[string]string, body io.Reader) (map[string]interface{}, error) {
	respMap := make(map[string]interface{})

	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, err
	}

	//关闭资源
	if req != nil && req.Body != nil {
		defer req.Body.Close()
	}

	// 这里的http header的设置是必须设置的.
	for h, v := range headers {
		req.Header.Set(h, v)
	}

	client := http.Client{}
	clientResponse, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	result, err := ioutil.ReadAll(clientResponse.Body)
	if err != nil {
		return nil, err
	}
	//fmt.Println(string(result))
	err = json.Unmarshal(result, &respMap)
	if err != nil {
		return nil, err
	}
	return respMap, nil
}

func GetRequest(url string, headers map[string]string) (map[string]interface{}, error) {
	respMap := make(map[string]interface{})

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	//关闭资源
	if req != nil && req.Body != nil {
		defer req.Body.Close()
	}

	// 这里的http header的设置是必须设置的.
	for h, v := range headers {
		req.Header.Set(h, v)
	}

	client := http.Client{}
	clientResponse, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	result, err := ioutil.ReadAll(clientResponse.Body)
	json.Unmarshal(result, &respMap)

	return respMap, nil
}

func RestRequest(method, url string, headers map[string]string, body io.Reader) (map[string]interface{}, error) {
	respMap := make(map[string]interface{})

	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}

	//关闭资源
	if req != nil && req.Body != nil {
		defer req.Body.Close()
	}

	// 这里的http header的设置是必须设置的.
	for h, v := range headers {
		req.Header.Set(h, v)
	}

	client := http.Client{}
	clientResponse, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	result, err := ioutil.ReadAll(clientResponse.Body)
	json.Unmarshal(result, &respMap)

	return respMap, nil
}
